#ifndef TRIGGERINGTIMER_H_INCLUDED
#define TRIGGERINGTIMER_H_INCLUDED

#include "Timer.h"
#include "../System/EventHandling.h"
#include <my/Config.h>

namespace my {

/**
* @class TriggeringTimer
* @brief Create a TriggeringTimer. A TriggeringTimer is a Timer that call a binded slot (function or class member) when it reaches zero.\n
* Lets see how we can use it with a simple function :\n
* @code
// The function needs to take no arguments and to return nothing
void foo(void)
{
    // Do something...
}

int main(void)
{
    my::TriggeringTimer timer(5.f, false, true); // Create a timer of 5.0 seconds, don't start it immediatly, set auto restarting
    timer.bind(foo); // Bind a function to call every 5.0 seconds

    timer.start(); // Start the timer
    while(true)
    {
        timer.update(); // Updating the timer so when it will be expired, the binded function will be called
        // foo() is automatically called after 5 seconds, and because of the auto-restarting, it will be
        // called every 5 seconds ! No need to check ourselves if the timer has expired !
    }

}
* @endcode
* The code above automatically call a function after a given time. \n \n
* This code do the same but with an object method (using boost::bind, already included) :
* @code
struct Foo
{
    void bar(void)
    {
        // Do something...
    }
};

int main(void)
{
    Foo my_foo; // Creating some foo stuff
    my::TriggeringTimer timer(5.f, false, true); // Create a timer of 5.0 seconds, don't start it immediatly, set auto restarting
    timer.bind(boost::bind(&Foo::bar, &my_foo)); // Bind a class method to call every 5.0 seconds

    timer.start(); // Start the timer
    while(true)
    {
        timer.update(); // Updating the timer so when it will be expired, the binded method will be called
        // my_foo.bar() is automatically called after 5 seconds, and because of the auto-restarting, it will be
        // called every 5 seconds ! No need to check ourselves if the timer has expired !
    }

}
* @endcode
* @see Timer
*/
class MYAPI TriggeringTimer : public my::Timer, public my::EventHandling
{
    public:
        /**
        * @brief Default Constructor. To use the Timer you will need to use reset(float timeLimit, bool continueRunning).
        */
        TriggeringTimer();

        /**
        * @brief Recommended constructor.
        * @param timeLimit The starting time of the Timer. It will decrease to zero.
        * @param initRunning Set it true if you want to start the timer at construction
        * @param loopRunning Set it true if you want to restart the time when expired
        */
        TriggeringTimer(float timeLimit, bool initRunning = false, bool loopRunning = false);

        /**
        * @brief Default destructor.
        */
        virtual ~TriggeringTimer();

        /**
        * @brief To set or unset the auto restarting
        * @param active Set ir true if you want to restart the timer when expired, else set it false
        */
        void    setLoopRunning(bool active = true);

        /**
        * @brief Is the loop running activated ?
        * @return true if the loop running is activated, else return false
        */
        bool    loopRunning() const;

        /**
        * @brief To reset the Timer
        * @param timeLimit The starting time of the Timer. It will decrease to zero.
        * @param keepRunning Set it true if you want to restart the timer
        */
        void    reset(float timeLimit, bool keepRunning = false);

        /**
        * @brief To reset the Timer, the old time limit will be kept
        * @param keepRunning Set it true if you want to restart the timer
        */
        void    reset(bool keepRunning = false);

        /**
        * @brief Bind the expiration of the time with a slot
        * @param function A my::slot to call at timer expiration. You can use boost::bind to bind a object member, else use a function.
        */
        void    bind(my::slot function);

        /**
        * @brief Update the timer and call the slot binded at expiration. Should be called once a main loop
        */
        void    update();

    private:
        bool    _alreadyExpired;
        bool    _loopRunning;
};

}

#endif // TRIGGERINGTIMER_H_INCLUDED
